package org.nnxy.foodboot.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.nnxy.foodboot.common.dto.ResponseInfo;
import org.nnxy.foodboot.service.StatisticsService;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 数据统计控制器
 * 提供食谱统计、用户交互统计、热门排行等API接口
 */
@RestController
@RequestMapping("/api/statistics")
@RequiredArgsConstructor
@Slf4j
@Tag(name = "数据统计相关接口", description = "提供食谱统计、用户交互统计、热门排行等数据查询功能")
@Validated
public class StatisticsController {

    private final StatisticsService statisticsService;

    /**
     * 获取食谱相关统计数据
     * 包括：食谱总数、分类分布、时间趋势等
     * 
     * @return 包含统计结果的响应对象，数据包含以下字段：
     *         - totalCount: 食谱总数
     *         - flavorDistribution: 口味分布
     *         - techniqueDistribution: 技巧分布
     *         - difficultyDistribution: 难度分布
     *         - categoryDistribution: 分类分布
     *         - trendData: 时间趋势数据
     */
    @GetMapping("/recipe")
    @Operation(summary = "获取食谱相关统计数据", description = "获取食谱总数、分类分布、时间趋势等统计数据")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "recipeStatistics", key = "'all'", unless = "#result.code != 200")
    public ResponseInfo<Map<String, Object>> getRecipeStatistics() {
        try {
            Map<String, Object> statistics = statisticsService.getRecipeStatistics();
            return ResponseInfo.success(statistics);
        } catch (Exception e) {
            log.error("获取食谱统计数据失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }

    /**
     * 获取用户交互相关统计数据
     * 包括：浏览量、收藏量、推荐点击量、时间趋势等
     * 
     * @param days 统计的天数，默认30天
     * @return 包含统计结果的响应对象，数据包含以下字段：
     *         - overview: 总览数据，包含browseCount、favoriteCount、recommendClickCount
     *         - browseTrend: 浏览趋势
     *         - favoriteTrend: 收藏趋势
     *         - recommendationTrend: 推荐点击率趋势
     */
    @GetMapping("/interaction")
    @Operation(summary = "获取用户交互相关统计数据", description = "获取浏览量、收藏量、推荐点击量、时间趋势等统计数据")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "参数错误"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "interactionStatistics", key = "#days", unless = "#result.code != 200")
    public ResponseInfo<Map<String, Object>> getInteractionStatistics(
            @Parameter(description = "统计的天数", example = "30") 
            @RequestParam(required = false, defaultValue = "30") @Min(1) @Max(365) Integer days) {
        try {
            Map<String, Object> statistics = statisticsService.getInteractionStatistics(days);
            return ResponseInfo.success(statistics);
        } catch (IllegalArgumentException e) {
            log.warn("获取用户交互统计参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取用户交互统计数据失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }

    /**
     * 获取热门食谱排行数据
     * 包括：浏览量最高、收藏最多、评分最高的食谱
     * 
     * @param limit 每项排行的显示数量，默认10
     * @return 包含统计结果的响应对象，数据包含以下字段：
     *         - mostViewed: 浏览量最高的食谱
     *         - mostFavorited: 收藏最多的食谱
     *         - highestRated: 评分最高的食谱
     *         - recentAdded: 最近添加的食谱
     */
    @GetMapping("/popular")
    @Operation(summary = "获取热门食谱排行数据", description = "获取浏览量最高、收藏最多、评分最高的食谱排行")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "参数错误"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "popularRecipes", key = "#limit", unless = "#result.code != 200")
    public ResponseInfo<Map<String, Object>> getPopularRecipes(
            @Parameter(description = "排行显示数量", example = "10") 
            @RequestParam(required = false, defaultValue = "10") @Min(1) @Max(100) Integer limit) {
        try {
            Map<String, Object> popularRecipes = statisticsService.getPopularRecipes(limit);
            return ResponseInfo.success(popularRecipes);
        } catch (IllegalArgumentException e) {
            log.warn("获取热门食谱数据参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取热门食谱数据失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取最近添加的食谱
     * 
     * @param limit 限制数量，默认10
     * @return 最近添加的食谱列表
     */
    @GetMapping("/recent")
    @Operation(summary = "获取最近添加的食谱", description = "获取最近添加的食谱列表")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "参数错误"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "recentRecipes", key = "#limit", unless = "#result.code != 200")
    public ResponseInfo<List<Map<String, Object>>> getRecentAddedRecipes(
            @Parameter(description = "限制数量", example = "10") 
            @RequestParam(required = false, defaultValue = "10") @Min(1) @Max(100) Integer limit) {
        try {
            List<Map<String, Object>> recentRecipes = statisticsService.getRecentAddedRecipes(limit);
            return ResponseInfo.success(recentRecipes);
        } catch (IllegalArgumentException e) {
            log.warn("获取最近添加食谱参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取最近添加食谱失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取食谱详情统计数据
     * 
     * @param recipeId 食谱ID
     * @return 食谱详情及统计数据
     */
    @GetMapping("/recipe/{recipeId}")
    @Operation(summary = "获取食谱详情统计数据", description = "获取食谱详情及其浏览量、收藏量、评分等统计数据")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "404", description = "食谱不存在"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "recipeDetailStats", key = "#recipeId", unless = "#result.code != 200")
    public ResponseInfo<Map<String, Object>> getRecipeDetailWithStats(
            @Parameter(description = "食谱ID", required = true) 
            @PathVariable @Min(1) Long recipeId) {
        try {
            Map<String, Object> recipeDetail = statisticsService.getRecipeDetailWithStats(recipeId);
            if (recipeDetail == null || recipeDetail.isEmpty()) {
                return ResponseInfo.error(404, "食谱不存在");
            }
            return ResponseInfo.success(recipeDetail);
        } catch (IllegalArgumentException e) {
            log.warn("获取食谱详情统计数据参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取食谱详情统计数据失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取月度食谱统计数据
     * 
     * @param year 年份，默认当前年
     * @return 月度统计数据
     */
    @GetMapping("/monthly")
    @Operation(summary = "获取月度食谱统计数据", description = "获取指定年份每月的食谱数量统计")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "参数错误"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "monthlyStats", key = "#year", unless = "#result.code != 200")
    public ResponseInfo<List<Map<String, Object>>> getMonthlyStats(
            @Parameter(description = "年份", example = "2023") 
            @RequestParam(required = false) @Min(2000) @Max(2100) Integer year) {
        try {
            int targetYear = year != null ? year : LocalDate.now().getYear();
            List<Map<String, Object>> monthlyStats = statisticsService.getRecipeStatsByMonth(targetYear);
            return ResponseInfo.success(monthlyStats);
        } catch (IllegalArgumentException e) {
            log.warn("获取月度统计数据参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取月度统计数据失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取食谱分类分布统计
     * 
     * @return 分类分布统计
     */
    @GetMapping("/category")
    @Operation(summary = "获取食谱分类分布统计", description = "获取各分类的食谱数量统计")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "categoryDistribution", unless = "#result.code != 200")
    public ResponseInfo<Map<String, Long>> getCategoryDistribution() {
        try {
            Map<String, Long> categoryDistribution = statisticsService.countByCategory();
            return ResponseInfo.success(categoryDistribution);
        } catch (Exception e) {
            log.error("获取分类分布统计失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取食谱口味分布统计
     * 
     * @return 口味分布统计
     */
    @GetMapping("/flavor")
    @Operation(summary = "获取食谱口味分布统计", description = "获取各口味的食谱数量统计")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "flavorDistribution", unless = "#result.code != 200")
    public ResponseInfo<Map<String, Long>> getFlavorDistribution() {
        try {
            Map<String, Long> flavorDistribution = statisticsService.countByFlavor();
            return ResponseInfo.success(flavorDistribution);
        } catch (Exception e) {
            log.error("获取口味分布统计失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取食谱技巧分布统计
     * 
     * @return 技巧分布统计
     */
    @GetMapping("/technique")
    @Operation(summary = "获取食谱技巧分布统计", description = "获取各技巧的食谱数量统计")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "techniqueDistribution", unless = "#result.code != 200")
    public ResponseInfo<Map<String, Long>> getTechniqueDistribution() {
        try {
            Map<String, Long> techniqueDistribution = statisticsService.countByTechnique();
            return ResponseInfo.success(techniqueDistribution);
        } catch (Exception e) {
            log.error("获取技巧分布统计失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取食谱难度分布统计
     * 
     * @return 难度分布统计
     */
    @GetMapping("/difficulty")
    @Operation(summary = "获取食谱难度分布统计", description = "获取各难度的食谱数量统计")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "difficultyDistribution", unless = "#result.code != 200")
    public ResponseInfo<Map<String, Long>> getDifficultyDistribution() {
        try {
            Map<String, Long> difficultyDistribution = statisticsService.countByDifficulty();
            return ResponseInfo.success(difficultyDistribution);
        } catch (Exception e) {
            log.error("获取难度分布统计失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取浏览趋势数据
     * 
     * @param days 统计天数，默认30天
     * @return 浏览趋势数据
     */
    @GetMapping("/trend/browse")
    @Operation(summary = "获取浏览趋势数据", description = "获取指定天数内的浏览量趋势数据")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "参数错误"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "browseTrend", key = "#days", unless = "#result.code != 200")
    public ResponseInfo<List<Map<String, Object>>> getBrowseTrend(
            @Parameter(description = "统计天数", example = "30") 
            @RequestParam(required = false, defaultValue = "30") @Min(1) @Max(365) Integer days) {
        try {
            List<Map<String, Object>> trend = statisticsService.getBrowseTrend(days);
            return ResponseInfo.success(trend);
        } catch (IllegalArgumentException e) {
            log.warn("获取浏览趋势数据参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取浏览趋势数据失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取收藏趋势数据
     * 
     * @param days 统计天数，默认30天
     * @return 收藏趋势数据
     */
    @GetMapping("/trend/favorite")
    @Operation(summary = "获取收藏趋势数据", description = "获取指定天数内的收藏量趋势数据")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "参数错误"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "favoriteTrend", key = "#days", unless = "#result.code != 200")
    public ResponseInfo<List<Map<String, Object>>> getFavoriteTrend(
            @Parameter(description = "统计天数", example = "30") 
            @RequestParam(required = false, defaultValue = "30") @Min(1) @Max(365) Integer days) {
        try {
            List<Map<String, Object>> trend = statisticsService.getFavoriteTrend(days);
            return ResponseInfo.success(trend);
        } catch (IllegalArgumentException e) {
            log.warn("获取收藏趋势数据参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取收藏趋势数据失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取推荐点击率趋势数据
     * 
     * @param days 统计天数，默认30天
     * @return 推荐点击率趋势数据
     */
    @GetMapping("/trend/recommendation")
    @Operation(summary = "获取推荐点击率趋势数据", description = "获取指定天数内的推荐点击率趋势数据")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "参数错误"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "recommendationTrend", key = "#days", unless = "#result.code != 200")
    public ResponseInfo<List<Map<String, Object>>> getRecommendationClickRateTrend(
            @Parameter(description = "统计天数", example = "30") 
            @RequestParam(required = false, defaultValue = "30") @Min(1) @Max(365) Integer days) {
        try {
            List<Map<String, Object>> trend = statisticsService.getRecommendationClickRateTrend(days);
            return ResponseInfo.success(trend);
        } catch (IllegalArgumentException e) {
            log.warn("获取推荐点击率趋势数据参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取推荐点击率趋势数据失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取热门浏览食谱列表
     * 
     * @param limit 限制数量，默认10
     * @return 浏览量最高的食谱列表
     */
    @GetMapping("/most-viewed")
    @Operation(summary = "获取热门浏览食谱列表", description = "获取浏览量最高的食谱列表")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "参数错误"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "mostViewedRecipes", key = "#limit", unless = "#result.code != 200")
    public ResponseInfo<List<Map<String, Object>>> getMostViewedRecipes(
            @Parameter(description = "限制数量", example = "10") 
            @RequestParam(required = false, defaultValue = "10") @Min(1) @Max(100) Integer limit) {
        try {
            List<Map<String, Object>> recipes = statisticsService.getMostViewedRecipes(limit);
            return ResponseInfo.success(recipes);
        } catch (IllegalArgumentException e) {
            log.warn("获取热门浏览食谱列表参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取热门浏览食谱列表失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取热门收藏食谱列表
     * 
     * @param limit 限制数量，默认10
     * @return 收藏最多的食谱列表
     */
    @GetMapping("/most-favorited")
    @Operation(summary = "获取热门收藏食谱列表", description = "获取收藏最多的食谱列表")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "参数错误"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "mostFavoritedRecipes", key = "#limit", unless = "#result.code != 200")
    public ResponseInfo<List<Map<String, Object>>> getMostFavoritedRecipes(
            @Parameter(description = "限制数量", example = "10") 
            @RequestParam(required = false, defaultValue = "10") @Min(1) @Max(100) Integer limit) {
        try {
            List<Map<String, Object>> recipes = statisticsService.getMostFavoritedRecipes(limit);
            return ResponseInfo.success(recipes);
        } catch (IllegalArgumentException e) {
            log.warn("获取热门收藏食谱列表参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取热门收藏食谱列表失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取高评分食谱列表
     * 
     * @param limit 限制数量，默认10
     * @return 评分最高的食谱列表
     */
    @GetMapping("/highest-rated")
    @Operation(summary = "获取高评分食谱列表", description = "获取评分最高的食谱列表")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "参数错误"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "highestRatedRecipes", key = "#limit", unless = "#result.code != 200")
    public ResponseInfo<List<Map<String, Object>>> getHighestRatedRecipes(
            @Parameter(description = "限制数量", example = "10") 
            @RequestParam(required = false, defaultValue = "10") @Min(1) @Max(100) Integer limit) {
        try {
            List<Map<String, Object>> recipes = statisticsService.getHighestRatedRecipes(limit);
            return ResponseInfo.success(recipes);
        } catch (IllegalArgumentException e) {
            log.warn("获取高评分食谱列表参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取高评分食谱列表失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取自定义时间范围内的统计数据
     * 
     * @param startDate 开始日期，格式：yyyy-MM-dd
     * @param endDate 结束日期，格式：yyyy-MM-dd，默认当前日期
     * @param type 统计类型，可选值：browse, favorite, recommendation，默认all
     * @return 指定时间范围的统计数据
     */
    @GetMapping("/custom-range")
    @Operation(summary = "获取自定义时间范围内的统计数据", description = "获取指定时间范围内的浏览、收藏、推荐点击统计数据")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "参数错误"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @Cacheable(value = "customRangeStats", key = "#startDate + '-' + #endDate + '-' + #type", unless = "#result.code != 200")
    public ResponseInfo<Map<String, Object>> getCustomRangeStats(
            @Parameter(description = "开始日期，格式：yyyy-MM-dd", required = true, example = "2023-01-01") 
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
            @Parameter(description = "结束日期，格式：yyyy-MM-dd", example = "2023-12-31") 
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate,
            @Parameter(description = "统计类型，可选值：browse, favorite, recommendation, all", example = "all") 
            @RequestParam(required = false, defaultValue = "all") String type) {
        try {
            // 结束日期默认为当前日期
            LocalDate end = endDate != null ? endDate : LocalDate.now();
            
            // 验证日期范围
            if (startDate.isAfter(end)) {
                return ResponseInfo.error(400, "开始日期不能晚于结束日期");
            }
            
            // 假设Service层有相应方法，可以根据实际情况调整
            Map<String, Object> stats = statisticsService.getCustomRangeStats(startDate, end, type);
            return ResponseInfo.success(stats);
        } catch (IllegalArgumentException e) {
            log.warn("获取自定义时间范围统计数据参数错误", e);
            return ResponseInfo.error(400, "参数错误: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取自定义时间范围统计数据失败", e);
            return ResponseInfo.error("获取统计数据失败: " + e.getMessage());
        }
    }
} 